#define DebugFilters

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using ObjectLib;
using System.Threading;
using StaticUtility;

namespace ObjectParser
{
	/// <summary>
	/// Summary description for FormFilter.
	/// </summary>
	public class FormFilter : System.Windows.Forms.Form
    {
        private IContainer components;
        private OpenFileDialog ofd;
		private System.Windows.Forms.MainMenu mainMenu1;
        private System.Windows.Forms.MenuItem menuItem1;
		private System.Windows.Forms.OpenFileDialog OfdAnim;
		private System.Windows.Forms.SaveFileDialog SfdAnim;
        private System.Windows.Forms.MenuItem mLoad;
		private System.Windows.Forms.MenuItem mSave;

		public Thread RenderingThread;
		public FilterResponseList FiltersTotal;
		public FilterResponseAnimation Result;
		public CategoryNode Category;
		public float ThresholdDistance, PathPrecision, RoiRadius;
		public PointF RoiCenter;
		public float[] threshes;
        private FilterFlowPanel.FilterFlowPanel filterFlowPanel1;
        private SplitContainer splitContainer1;
    
		public delegate void FinishedRendering();
		public FinishedRendering OnFinishRendering=null;

		public FormFilter( FormParse Owner, 
			OpenFileDialog ofdFilterDialog, FinishedRendering OnFinishRendering,
			CategoryNode Category, PointF RoiCenter, float RoiRadius)
		{
			ofd = ofdFilterDialog;
			this.Owner = Owner;
			this.Category = Category;
			this.RoiCenter = RoiCenter;
			this.RoiRadius = RoiRadius;
			this.OnFinishRendering = OnFinishRendering;
			
			InitializeComponent();
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
            this.components = new System.ComponentModel.Container();
            this.mainMenu1 = new System.Windows.Forms.MainMenu(this.components);
            this.menuItem1 = new System.Windows.Forms.MenuItem();
            this.mLoad = new System.Windows.Forms.MenuItem();
            this.mSave = new System.Windows.Forms.MenuItem();
            this.OfdAnim = new System.Windows.Forms.OpenFileDialog();
            this.SfdAnim = new System.Windows.Forms.SaveFileDialog();
            this.filterFlowPanel1 = new FilterFlowPanel.FilterFlowPanel();
            this.splitContainer1 = new System.Windows.Forms.SplitContainer();
            this.splitContainer1.Panel1.SuspendLayout();
            this.splitContainer1.SuspendLayout();
            this.SuspendLayout();
            // 
            // mainMenu1
            // 
            this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
            this.menuItem1});
            // 
            // menuItem1
            // 
            this.menuItem1.Index = 0;
            this.menuItem1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
            this.mLoad,
            this.mSave});
            this.menuItem1.Text = "File";
            // 
            // mLoad
            // 
            this.mLoad.Index = 0;
            this.mLoad.Text = "Load...";
            this.mLoad.Click += new System.EventHandler(this.mLoad_Click);
            // 
            // mSave
            // 
            this.mSave.Index = 1;
            this.mSave.Text = "Save...";
            this.mSave.Click += new System.EventHandler(this.mSave_Click);
            // 
            // OfdAnim
            // 
            this.OfdAnim.Title = "Load Animation or Single Frame";
            // 
            // filterFlowPanel1
            // 
            this.filterFlowPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.filterFlowPanel1.Location = new System.Drawing.Point(0, 0);
            this.filterFlowPanel1.Name = "filterFlowPanel1";
            this.filterFlowPanel1.Size = new System.Drawing.Size(114, 134);
            this.filterFlowPanel1.TabIndex = 0;
            // 
            // splitContainer1
            // 
            this.splitContainer1.Location = new System.Drawing.Point(12, 12);
            this.splitContainer1.Name = "splitContainer1";
            // 
            // splitContainer1.Panel1
            // 
            this.splitContainer1.Panel1.Controls.Add(this.filterFlowPanel1);
            this.splitContainer1.Size = new System.Drawing.Size(386, 134);
            this.splitContainer1.SplitterDistance = 114;
            this.splitContainer1.TabIndex = 1;
            // 
            // FormFilter
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(486, 323);
            this.Controls.Add(this.splitContainer1);
            this.Menu = this.mainMenu1;
            this.Name = "FormFilter";
            this.Text = "Select Filter Set";
            this.Closed += new System.EventHandler(this.FormFilter_Closed);
            this.splitContainer1.Panel1.ResumeLayout(false);
            this.splitContainer1.ResumeLayout(false);
            this.ResumeLayout(false);

		}
		#endregion

		private void butSelectFilters_Click(object sender, System.EventArgs e)
		{
			ofd.Title = "Please select the filter definition file.";
			ofd.Multiselect = false;
			//ofd.Filter = "Binary Format|*.FilterResponseList|Text Format|*.*";
			ofd.Filter = "Text Format|*.*|Binary Format|*.FilterResponseList";
			if(ofd.ShowDialog(this)==DialogResult.OK)
			{
				Cursor oldCursor = Cursor.Current;
				Cursor.Current = Cursors.WaitCursor;
				FiltersTotal = null;
				try
				{
					if(ofd.FilterIndex==2)
						FiltersTotal = FilterResponseList.DeserializeBinary(ofd.FileName);
					else
						FiltersTotal = FilterResponseList.FromTextFile(ofd.FileName);
				}
				catch(Exception ex)
				{
					MessageBox.Show(this, "Error while trying to open a filter response file.  "+ex.Message);
				}
				if(FiltersTotal!=null)
				{
					//	Carry on
					Result = new FilterResponseAnimation(ofd.FileName, FiltersTotal);
					//	Rewrite the label.
					labelSelectFilters.Text = Convert.ToString(FiltersTotal.Count)
						+ " from " + ofd.FileName;
					labelSelectFilters.Refresh();
					butOk.Enabled=true;
				}
				else
					butOk.Enabled=false;
				Cursor.Current=oldCursor;
			}
		}

		public void UpdateDelegate(float progress)
		{
			int prog = (int)(progress*(float)(progressBar1.Maximum-progressBar1.Minimum))+progressBar1.Minimum;
			if(prog < progressBar1.Value)
			{
				progressBar1.Value=prog;
				progressBar1.Refresh();
			}
			while(prog > progressBar1.Value)
			{
				progressBar1.PerformStep();
				progressBar1.Refresh();
			}
		}
		private void butOk_Click(object sender, System.EventArgs e)
		{
			bool proceed = true;
			float thresh, path, from=0.0f, to=0.0f, every=0.0f;
			try
			{
				path = Convert.ToSingle(this.textPrecision.Text);
				if(path>0.0f)
					this.PathPrecision = path;
				else
				{
					proceed = false;
					MessageBox.Show(this, "Precision must be a positive floating point number.");
				}
			}
			catch
			{
				proceed = false;
				MessageBox.Show(this, "Precision must be a positive floating point number.");
			}
			if(proceed)
			{
				try
				{
					thresh = Convert.ToSingle(this.textThresholdDist.Text);
					if(thresh>0.0f)
						this.ThresholdDistance = thresh;
					else
					{
						proceed = false;
						MessageBox.Show(this, "Distance threshold must be a positive floating point number.");
					}
				}
				catch
				{
					proceed = false;
					MessageBox.Show(this, "Distance threshold must be a positive floating point number.");
				}
			}
			if(this.radioOneFrame.Checked)
			{
				if(proceed)
				{
					try
					{
						threshes = new float[] {Convert.ToSingle(this.textThresholdSpikes.Text)};
						if(threshes[0]<0.0f)
						{
							proceed = false;
							MessageBox.Show(this, "Spike threshold must be a non-negative floating point number.");
						}
					}
					catch
					{
						proceed = false;
						MessageBox.Show(this, "Spike threshold must be a positive floating point number.");
					}
				}
				if(proceed==true)
				{
					progressBar1.Value=progressBar1.Minimum;

					RenderingThread = new Thread(new ThreadStart(Render));
					RenderingThread.Start();
					
					progressBar1.Value=progressBar1.Minimum;

					this.DialogResult = DialogResult.OK;
				}
			}
			else if(this.radioAnimate.Checked)
			{
				if(proceed)
				{
					try
					{
						from = Convert.ToSingle(this.textFrom.Text);
						if(from<0.0f)
						{
							proceed = false;
							MessageBox.Show(this, "Animation 'From' must be a non-negative floating point number.");
						}
					}
					catch
					{
						proceed = false;
						MessageBox.Show(this, "Animation 'From' must be a non-negative floating point number.");
					}
				}
				if(proceed)
				{
					try
					{
						to = Convert.ToSingle(this.textTo.Text);
						if(to<=0.0f)
						{
							proceed = false;
							MessageBox.Show(this, "Animation 'To' must be a non-negative floating point number.");
						}
					}
					catch
					{
						proceed = false;
						MessageBox.Show(this, "Animation 'To' must be a non-negative floating point number.");
					}
				}
				if(proceed)
				{
					try
					{
						every = Convert.ToSingle(this.textEvery.Text);
						if(every<=0.0f)
						{
							proceed = false;
							MessageBox.Show(this, "Animation 'Every' must be a positive floating point number.");
						}
					}
					catch
					{
						proceed = false;
						MessageBox.Show(this, "Animation 'Every' must be a positive floating point number.");
					}
				}
				if(proceed)
				{
					progressBar1.Value=progressBar1.Minimum;

					if(to<from)
						every = -every;
					threshes = Util.LinSpace(from,to,every);

					Result.Thresholds = threshes;

					RenderingThread = new Thread(new ThreadStart(Render));
					RenderingThread.Start();

					this.DialogResult = DialogResult.OK;
				}
			}
			if(proceed!=true)
				this.DialogResult = DialogResult.None;
		}
		private void Render()
		{
			Result.ConstructAnimation(threshes, this.Category, new Util.ProgressUpdater(UpdateDelegate),
				this.PathPrecision, this.ThresholdDistance, this.RoiCenter, this.RoiRadius, 2.5f*this.RoiRadius);
			
			progressBar1.Value=progressBar1.Minimum;

			OnFinishRendering();
		}
		private void radioOneFrame_CheckedChanged(object sender, System.EventArgs e)
		{
			RadioUpdate();
		}

		private void radioAnimate_CheckedChanged(object sender, System.EventArgs e)
		{
			RadioUpdate();
		}
		public void RadioUpdate()
		{
			textFrom.Enabled = textTo.Enabled = textEvery.Enabled = !radioOneFrame.Checked;
			this.textThresholdSpikes.Enabled = radioOneFrame.Checked;
		}

		private void mLoad_Click(object sender, System.EventArgs e)
		{
		}
        private void mSave_Click(object sender, System.EventArgs e)
        {
        }
		public void UpdateForm()
		{
			if(Result!=null)
			{
				this.labelSelectFilters.Text = Result.FilterFilename;
				this.textPrecision.Text = Convert.ToString(Result.PathPrecision);
				this.textThresholdDist.Text = Convert.ToString(Result.DistanceThreshold);
				if(Result.IsAnimation)
				{
					this.radioAnimate.Checked=true;
					this.radioOneFrame.Checked=false;
					RadioUpdate();

					this.textFrom.Text = Convert.ToString(Result.Thresholds[0]);
					this.textEvery.Text = Convert.ToString(Result.Thresholds[1]-Result.Thresholds[0]);
					this.textTo.Text = Convert.ToString(Result.Thresholds[Result.Thresholds.Length-1]);
				}
				else if(Result.IsSingleFrame)
				{
					this.radioAnimate.Checked=false;
					this.radioOneFrame.Checked=true;
					RadioUpdate();

					this.textThresholdSpikes.Text = Convert.ToString(Result.Thresholds[0]);
				}
			}
		}

		private void FormFilter_Closed(object sender, System.EventArgs e)
		{
			if(RenderingThread!=null)
				RenderingThread.Abort();
			RenderingThread=null;
		}

		private void butAbort_Click(object sender, System.EventArgs e)
		{
			if(RenderingThread!=null)
				RenderingThread.Abort();
			RenderingThread=null;
			progressBar1.Value=progressBar1.Minimum;
		}
	}
}
